#include <cstdio>
#include "Queue.h"

namespace zg_util{
    QueueItem* Queue::Dequeue() {
        return DequeueImpl();
    }

    QueueItem* Queue::TryDequeue(int msec) {
        return DequeueImpl(false,msec);
    }

    QueueItem* Queue::DequeueImpl(bool block, int msec) {
        QueueItem* pQi=NULL;
        WaitInfo* pWi=NULL;
        _mutex.lock();
        pQi=dequeue_one();

        if(pQi) {
            _mutex.unlock();
            return pQi;
        }
        pWi=new WaitInfo;
        _wait_queue.push_back(pWi);
        _mutex.unlock();
        if(block) {
            pWi->ev.wait();
        }else{
            if(!pWi->ev.wait(msec)) {
                _mutex.lock();
                for (deque<WaitInfo *>::iterator it = _wait_queue.begin(); it != _wait_queue.end(); it++) {
                    if (*it == pWi) {
                        _wait_queue.erase(it);
                        break;
                    }
                }
                _mutex.unlock();
            }
        }
        pQi=pWi->pData;
        delete pWi;
        return pQi;
    }
    void Queue::Enqueue(QueueItem* item) {
        _mutex.lock();
        if(_wait_queue.empty()){
            _data_queue.push_back(item);
        }else{
            WaitInfo *pWi=_wait_queue.front();
            _wait_queue.pop_front();
            pWi->pData=item;
            pWi->ev.set();
        }
        _mutex.unlock();
    }

    QueueItem* Queue::dequeue_one() {
        QueueItem* pQi=NULL;
        if(!_data_queue.empty()){
            pQi=_data_queue.front();
            _data_queue.pop_front();
        }
        return pQi;
    }

    void Queue::Clear() {
        _mutex.lock();
        _data_queue.clear();
        _wait_queue.clear();
        _mutex.unlock();
    }
#if __cplusplus >= 201103L
    void Queue::ShrinkToFit() {
        _mutex.lock();
        _data_queue.shrink_to_fit();
        _wait_queue.shrink_to_fit();
        _mutex.unlock();
    }
#endif
}